package org.crl.blogsystem.service;

import cn.dev33.satoken.stp.StpUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.checkerframework.checker.units.qual.A;
import org.crl.blogsystem.controller.BlogController;
import org.crl.blogsystem.entity.Blog;
import org.crl.blogsystem.entity.Media;
import org.crl.blogsystem.entity.User;
import org.crl.blogsystem.entity.UserFollow;
import org.crl.blogsystem.entity.dto.BlogCreateDTO;
import org.crl.blogsystem.entity.dto.BlogDTO;
import org.crl.blogsystem.entity.dto.MediaDTO;
import org.crl.blogsystem.message.ResponseMessage;
import org.crl.blogsystem.repository.BlogRepository;
import org.crl.blogsystem.repository.UserFollowRepository;
import org.crl.blogsystem.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
public class BlogService implements IBlogService{
    private static final Logger log = LoggerFactory.getLogger(BlogController.class);

    @Autowired
    BlogRepository blogRepository;

    @Autowired
    MediaService mediaService;

    @Autowired
    UserFollowRepository userFollowRepository;

    @Autowired
    IUserService userService;

    @Autowired
    IMinioService minioService;


    @Autowired
    ObjectMapper objectMapper;

    public BlogDTO blogConvert(Blog blog, List<MediaDTO> mediaDTOS) {
        BlogDTO dto = new BlogDTO();
        dto.setId(blog.getId());
        dto.setContent(blog.getContent());
        dto.setCreatedAt(blog.getCreatedAt());
        dto.setLikesCount(blog.getLikesCount());
        dto.setPrivateKey(blog.getPrivateKey());
        dto.setUserId(blog.getUser().getId());
        dto.setUsername(blog.getUser().getUsername());
        dto.setAvatar(blog.getUser().getAvatar());
        dto.setMediaList(mediaDTOS);
        dto.setCommentsCount(blog.getCommentsCount());
        dto.setIsMyself(blog.getUser().getId().equals(StpUtil.getLoginIdAsLong()));
        UserFollow userFollow = userFollowRepository.findByFollowerIdAndFollowingId(StpUtil.getLoginIdAsLong(), blog.getUser().getId());
        dto.setIsFollowed(userFollow.getState() == 1);
        return dto;
    }

    @Override
    public ResponseMessage<BlogDTO> createBlog(BlogCreateDTO blogCreateDTO, List<MultipartFile> images) {
        try {
            Blog blog = new Blog();
            Long userId = StpUtil.getLoginIdAsLong();
            LocalDateTime now = LocalDateTime.now();

            if (blogCreateDTO.getContent() == null || blogCreateDTO.getContent().isEmpty()) {
                blog.setContent("分享图片");
            } else {
                blog.setContent(blogCreateDTO.getContent());
            }

            blog.setUser(userService.getById(userId));
            blog.setCreatedAt(now);
            blog.setState(1);
            blog.setLikesCount(0);
            blog.setCommentsCount(0);
            blog.setPrivateKey(blogCreateDTO.getPrivateKey());

            Blog savedBlog = blogRepository.save(blog);

            List<Media> mediaList = new ArrayList<>();
            List<MediaDTO> mediaDTOS = new ArrayList<>();

            if (images != null && !images.isEmpty()) {
                for (MultipartFile image : images) {
                    String folder = "/blog/" + userId + "/" + savedBlog.getId() + now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    String url = minioService.uploadFile(folder, image);
                    if (url != null) {
                        Media media = new Media();
                        media.setUrl(url);
                        media.setBlog(savedBlog);
                        MediaDTO dto = mediaService.save(media);
                        mediaList.add(media);
                        mediaDTOS.add(dto);
                    }
                }
            }

            savedBlog.setMediaList(mediaList);
            savedBlog = blogRepository.save(savedBlog);

            BlogDTO blogDTO = blogConvert(savedBlog, mediaDTOS);
            return ResponseMessage.success(blogDTO);
        } catch (Exception e) {
            log.error("Failed to create blog", e);
            return ResponseMessage.fail("Invalid request data: " + e.getMessage());
        }
    }


    private String saveImageToFileSystem(MultipartFile file) {
        // TODO: 2023/5/23 保存图片到文件系统
        try {
            String upLoadDir = "uploads/";
            File dir = new File(upLoadDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            String fileName = UUID.randomUUID() + "-" + file.getOriginalFilename();
            String filePath = upLoadDir + fileName;
            file.transferTo(new File(filePath));
            return "/uploads/" + fileName;
        } catch (IOException e) {
            throw new RuntimeException("文件保存失败" + e);
        }
    }

    @Override
    public void delete(Long id) {
        Blog blog = blogRepository.findById(id).orElseThrow(() -> new RuntimeException("该博客不存在"));
        blog.setState(0);
        blogRepository.save(blog);
    }

    /**
     * 获取我的所有博客
     * @return List<Blog>
     */
    @Override
    public List<Blog> getByUser() {
        Long userId = StpUtil.getLoginIdAsLong();
        List<Blog> blogList = blogRepository.findAllByUserIdOrderByCreatedAtDesc(userId);
        return blogList != null ? blogList : null;
    }

    /**
     * 获取用户所有博客
     * 权限集合：0
     * @param userId
     * @return
     */
    @Override
    public List<Blog> getByUser(Long userId) {
        Long currentUserId = StpUtil.getLoginIdAsLong();
        Set<Integer> privateKeys = new HashSet<>();
        privateKeys.add(0);
        if (currentUserId.equals(userId)) {
            privateKeys.add(0);
            privateKeys.add(1);
            privateKeys.add(2);
        } else {
            // 否则只看公开和关注可见的
            privateKeys.add(0);
            if (userService.isFollowing(userId)) {
                privateKeys.add(2); // 若关注，则加上权限2
            }
        }
        if (userId != null) {
            return blogRepository.findAllByUser_IdAndPrivateKeyInOrderByCreatedAtDesc(userId, privateKeys);
        }
        return null;
    }

    /**
     * 获取所关注用户的所有博客
     * 权限集合：0, 2
     * @param following
     * @return
     */
    @Override
    public List<Blog> getByUserSet(Set<User> following) {
        Set<Integer> privateKey = new HashSet<>();
        privateKey.add(0);
//        privateKey.add(2);
        List<Blog> blogList = new ArrayList<>(blogRepository.findAllByPrivateKeyIn(privateKey));
//        List<Blog> myBlogList = new ArrayList<>(blogRepository.findAllByUserId(StpUtil.getLoginIdAsLong()));
//        blogList.addAll(myBlogList);
//        blogList.sort((b1, b2) -> b2.getCreatedAt().compareTo(b1.getCreatedAt()));
        return blogList;
    }

    /**
     * 获取所有用户的所有博客
     * 权限集合：0
     * @return
     */
    @Override
    public List<Blog> getHotBlogs(Integer limit) {
        List<Blog> allBlogs = blogRepository.findHotBlogs();
        if (limit != null && allBlogs.size() > limit) {
            return allBlogs.subList(0, limit);
        }
        log.info("allBlogs: " + allBlogs);
        return allBlogs;
    }

    @Override
    public List<Blog> search(String key) {
        if (key != null) {
            return blogRepository.findAllByContentContainingAndPrivateKeyOrderByCreatedAtDesc(key, 0);
        }
        return null;
    }

    @Override
    public Blog save(Blog blog) {
        return blogRepository.save(blog);
    }

    @Override
    public Blog getById(Long blogId) {
        return blogRepository.findById(blogId).orElse(null);
    }

    @Override
    public Blog update(Long id, Integer privateKey) {
        Blog blog = blogRepository.findById(id).orElseThrow(() -> new RuntimeException("该博客不存在"));
        blog.setPrivateKey(privateKey);
        return blogRepository.save(blog);
    }
}
